package com.googlecode.continuity.plugin.gwtext.client;

import com.google.gwt.user.client.ui.*;
import com.googlecode.continuity.core.client.CoreGWT;

/**
 * StarRating
 *
 * @author Peter Schmitt <aragos@aragos.de>
 */
public class StarRating extends RatingControl {
// ------------------------------ FIELDS ------------------------------

  private float rating;
  private boolean selectable;
  private int selected;
  private int lastSelected;

  private HorizontalPanel container;

// --------------------------- CONSTRUCTORS ---------------------------

  public StarRating() {
    this(0, true);
  }

  public StarRating(float rating, boolean selectable) {
    Image.prefetch(CoreGWT.getWebappRoot() + "img/emptystar.png");
    Image.prefetch(CoreGWT.getWebappRoot() + "img/fullstar.png");
    Image.prefetch(CoreGWT.getWebappRoot() + "img/semistar.png");

    container = new HorizontalPanel();
    final FocusPanel focus = new FocusPanel(container);

    focus.addMouseListener(new MouseListenerAdapter() {
      public void onMouseLeave(Widget widget) {
        setSelected(0);
        super.onMouseLeave(widget);
      }
    });

    focus.addFocusListener(new FocusListenerAdapter() {
      public void onFocus(Widget widget) {
        focus.setFocus(false);
      }
    });

    focus.addStyleName("starRating");
    initWidget(focus);

    for (int i = 0; i < 5; i++) {
      Image star = new Image(CoreGWT.getWebappRoot() + "img/emptystar.png");
      star.addStyleName("star");
      star.addMouseListener(new MouseListenerAdapter() {
        public void onMouseEnter(Widget widget) {
          if (StarRating.this.selectable) {
            setSelected(container.getWidgetIndex(widget) + 1);
          }
        }
      });
      star.addClickListener(new ClickListener() {
        public void onClick(Widget widget) {
          if (StarRating.this.selectable) {
            rate(container.getWidgetIndex(widget) + 1);
          }
        }
      });
      container.add(star);
    }

    setRating(rating);
    setSelectable(selectable);
    selected = 0;
    setSelected(0);
  }

  private void rate(int rating) {
    selected = 0;
    setRating(rating);
    fireRating(rating);
  }

  public void setRating(float rating) {
    // TODO: catch rating over 5.0
    this.rating = rating;
    updateDisplay();
  }

  private void updateDisplay() {
    int roundedRating = Math.round(rating);
    for (int i = lastSelected; i < selected && lastSelected < selected; i++) {
      ((Image) container.getWidget(i)).setUrl(CoreGWT.getWebappRoot() + "img/semistar.png");
    }
    for (int i = selected; i < roundedRating && selected <= lastSelected; i++) {
      ((Image) container.getWidget(i)).setUrl(CoreGWT.getWebappRoot() + "img/fullstar.png");
    }
    for (int i = Math.max(roundedRating, selected); i < 5 && selected <= lastSelected; i++) {
      ((Image) container.getWidget(i)).setUrl(CoreGWT.getWebappRoot() + "img/emptystar.png");
    }
  }

  public void setSelectable(boolean selectable) {
    this.selectable = selectable;
    updateDisplay();
    if (selectable) {
      container.addStyleName("selectable");
    } else {
      container.removeStyleName("selectable");
    }
  }

  private void setSelected(int selected) {
    lastSelected = this.selected;
    this.selected = selected;
    if (lastSelected != selected) {
      updateDisplay();
    }
  }

// --------------------- GETTER / SETTER METHODS ---------------------

  public float getRating() {
    return rating;
  }

  public boolean isSelectable() {
    return selectable;
  }
}
